/**
 * Create in 2012-4-17.
 */
package kit4j.ui.cs.awt;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.concurrent.TimeUnit;

import kit4j.common.task.StepTask.StepTaskCallback;
import kit4j.common.task.Task;
import kit4j.common.task.TimeTask;
import kit4j.common.task.executor.SequentialTaskExecutor;
import kit4j.common.task.executor.TaskExecutor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 组件的可见动态操作者类型。该类型提供对{@link java.awt.Component}类型对象的可见的动态变化操作方法，如从起始点移动到目标点的{@link #move(Point, Point, Point)}
 * 方法，从初始尺寸伸缩到目标尺寸的{@link #stretch(Dimension, Dimension, Dimension)}方法等。
 * 
 * @author MiniKnife
 * 
 */
public class DynamicComponentHandler {
	
	private static final Logger log = LoggerFactory.getLogger(DynamicComponentHandler.class);

	/**
	 * 需要进行动态变化的组件对象。
	 */
	private Component component;

	/**
	 * 任务操作的执行器。
	 */
	private TaskExecutor executor;

	/**
	 * 间隔时间的单元粒度。
	 */
	private TimeUnit timeUnit;

	/**
	 * 操作开始前等待的时间单元数。
	 */
	private long initialDelay;

	/**
	 * 每一步操作间隔的时间单元数。
	 */
	private long delay;

	/**
	 * 创建一个组件的可见动态操作者对象。
	 * 
	 * @param component
	 *            要操作的组件对象
	 */
	public DynamicComponentHandler(Component component) {
		this.component = component;
		executor = new SequentialTaskExecutor();
		timeUnit = TimeUnit.SECONDS;
		initialDelay = 0;
		delay = 0;
	}

	/**
	 * 移动绑定的组件。
	 * 
	 * @param initLocation
	 *            组件移动的起始位置
	 * @param targetLocation
	 *            组件移动的目标终点位置
	 * @param locationIncrement
	 *            组件移动的坐标增量
	 */
	public void move(Point2D initLocation, Point2D targetLocation, Point2D locationIncrement) {
		log.debug("Move component from ({}) to ({}), increment by ({})", new Object[] {initLocation, targetLocation, locationIncrement});
		
		Task moveTask = createMoveTask(initLocation, targetLocation, locationIncrement);

		initComponentVisible();
		executeTask(moveTask);
	}

	/**
	 * 创建针对绑定组件的移动任务。
	 * 
	 * @param initLocation
	 *            组件移动的起始位置
	 * @param targetLocation
	 *            组件移动的目标终点位置
	 * @param locationIncrement
	 *            组件移动的坐标增量
	 * @return 针对绑定组件的移动任务
	 */
	private Task createMoveTask(final Point2D initLocation, final Point2D targetLocation,
			final Point2D locationIncrement) {
		StepTaskCallback mover = new DynamicComponentStepMover(getComponent(), initLocation, targetLocation,
				locationIncrement);
		TimeTask task = new TimeTask(mover);

		task.setTimeUnit(getTimeUnit());
		task.setInitialDelay(getInitialDelay());
		task.setDelay(getDelay());

		return task;
	}
	
	protected void initComponentVisible() {
		if(!getComponent().isVisible()) {
			getComponent().setVisible(true);
		}
	}

	/**
	 * 伸缩绑定的组件。
	 * 
	 * @param initialSize
	 *            组件对象伸缩的初始尺寸
	 * @param targetSize
	 *            组件对象要伸缩到的目标尺寸
	 * @param sizeIncrement
	 *            伸缩过程中的尺寸增量
	 */
	public void stretch(Dimension initialSize, Dimension targetSize, Dimension sizeIncrement) {
		Task stretchTask = createStretchTask(initialSize, targetSize, sizeIncrement);

		initComponentVisible();
		executeTask(stretchTask);
	}

	/**
	 * 创建针对绑定组件对象的伸缩任务。
	 * 
	 * @param initialSize
	 *            组件对象伸缩的初始尺寸
	 * @param targetSize
	 *            组件对象要伸缩到的目标尺寸
	 * @param sizeIncrement
	 *            伸缩过程中的尺寸增量
	 * @return 针对绑定组件对象的伸缩任务
	 */
	private Task createStretchTask(final Dimension initialSize, final Dimension targetSize,
			final Dimension sizeIncrement) {
		StepTaskCallback stretcher = new DynamicComponentStepStretcher(getComponent(), initialSize, targetSize,
				sizeIncrement);
		TimeTask task = new TimeTask(stretcher);

		task.setTimeUnit(getTimeUnit());
		task.setInitialDelay(getInitialDelay());
		task.setDelay(getDelay());

		return task;
	}

	/**
	 * 提交运行任务。
	 * 
	 * @param task
	 *            要运行的任务
	 */
	protected void executeTask(Task task) {
		executor.removeAllTasks();
		executor.addTask(task);
		executor.start();
	}
	
	/**
	 * 等待所有的操作完成。在所有的操作完成之前，该方法将一直阻塞。
	 */
	public void waitForAll() {
		executor.waitForAllTasksComplete();
	}

	/**
	 * @return the component
	 */
	public Component getComponent() {
		return component;
	}

	/**
	 * @param component
	 *            the component to set
	 */
	public void setComponent(Component component) {
		this.component = component;
	}

	/**
	 * @return the executor
	 */
	public TaskExecutor getTaskExecutor() {
		return executor;
	}

	/**
	 * @param executor
	 *            the executor to set
	 */
	public void setTaskExecutor(TaskExecutor executor) {
		this.executor = executor;
	}

	/**
	 * @return the timeUnit
	 */
	public TimeUnit getTimeUnit() {
		return timeUnit;
	}

	/**
	 * @param timeUnit
	 *            the timeUnit to set
	 */
	public void setTimeUnit(TimeUnit timeUnit) {
		this.timeUnit = timeUnit;
	}

	/**
	 * @return the initialDelay
	 */
	public long getInitialDelay() {
		return initialDelay;
	}

	/**
	 * @param initialDelay
	 *            the initialDelay to set
	 */
	public void setInitialDelay(long initialDelay) {
		this.initialDelay = initialDelay;
	}

	/**
	 * @return the delay
	 */
	public long getDelay() {
		return delay;
	}

	/**
	 * @param delay
	 *            the delay to set
	 */
	public void setDelay(long delay) {
		this.delay = delay;
	}

}
